# coding:utf-8
import base64
import concurrent
import os
import random
import re
import shutil
import sqlite3
import threading
import time
import traceback
import uuid
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
from io import BytesIO
from multiprocessing import Process
from urllib.parse import urlparse, parse_qs

import requests
import schedule
from PySide2.QtCore import QDateTime, Qt
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger

from DataBase import DatabaseManager, DatabaseWorker
from common.log import logger_1, logger_2
from config import conf
from Connector import WooXinAi
from lib import itchat
from lib.itchat.content import TEXT, PICTURE, RECORDING, NOTE, VIDEO, CARD, SHARING, MAP, ATTACHMENT
from TextProcess import cut_text, split_text_with_links, download_file_from_url

TYPE_SPEED = 9  # 模拟打字速度，给回复加上延迟，数值越大，回复速度越快
WORDS_COUNT = 300  # 当文本长度超过WORDS_COUNT时，进行拆分


class Friends:
    def __init__(self, members_list):
        self.members_list = members_list
        self.friends_list = None

    def read_friends(self, filename):
        friends = []
        with open(filename, 'r') as file:
            for line in file:
                name, status = line.strip().split(',')
                # friends.append(Friend(name, status))
        return friends

    def write_friends(self, friends, filename):
        with open(filename, 'w') as file:
            for friend in friends:
                file.write(f"{friend.name},{friend.status}\n")


class WeChatBot(Process):
    def __init__(self, queue_1, queue_2, queue_3, index):
        super().__init__()

        self.my_info = None
        self.db_manager = None
        self.db_worker = None
        self.uin = None
        self.user_name = None
        self.nick_name = None
        self.remark_name = None
        self.sex = None
        self.province = None
        self.city = None
        self.attr_status = None
        self.head_img_url = None
        self.seq = None
        self.friends = None
        self.remark_lists = None
        self.friends_show_list = None
        self.group_list = None

        self.friends_syn_num = 0
        self.friends_total_num = None

        self.queue_1 = queue_1  # 向主进程发送消息
        self.queue_2 = queue_2  # 接收来自主进程的消息
        self.queue_3 = queue_3  # 向好友界面发送消息
        self.index = index

        self.wooxin_ai = WooXinAi(self.index)
        # self.wooxin_ai.getToken()  # 确保有token
        self.member_list = []
        self.friends_show_list = []

        # 不回复的语气词
        # self.keywords = conf().get("keywords")

        self.message_hour_1 = int(conf().get("message_hour_1"))
        self.message_hour_2 = int(conf().get("message_hour_2"))
        self.message_interval = int(conf().get("message_interval"))

        # 定时任务的job_id
        self.job_id_message = None
        self.job_id_friends = None
        self.job_id_friends_night = None

        self.scheduler = None

        self.download_thread = None

        # 是否在线标志
        self.login_success = None

        # 计时器
        self.user_timers = {}  # 存储用户名与计时器
        self.user_messages = {}  # 存储用户名与消息

        self.logger = None
        self.logger_choose(self.index)

        # 设置用户回复字典，键为username，值为0，1，2
        # 值为0时，表示空闲状态，可回复可追问；值为1时，表示正在回复，追问等待；值为2时，表示正在追问，回复等待
        self.reply_sending_dic = {}

        # 是否主动登出，默认为False
        self.voluntary_logout = False

        # 储存标记为C的UserName
        self.c_user_name_dict = {}

    def logger_choose(self, index):
        if index == 1:
            self.logger = logger_1
        elif index == 2:
            self.logger = logger_2

    def check_key(self):
        # 首先检查 key 是否正在使用
        return self.wooxin_ai.getToken()

    def initialize(self):
        """
        获取登录用户的信息与好友的信息
        首次登录时执行
        """
        try:
            # 获取好友列表
            lists = itchat.get_friends(update=True)
            user = lists.pop(0)

            # 获取群聊信息
            groups = itchat.get_chatrooms(update=True)
            self.friends_total_num = len(lists)
            self.update_user_info(user, init=True)  # 获取个人用户信息
            self.update_friends_info_in_batches(lists)  # 批量获取好友信息
            self.update_groups_info(groups)  # 获取群聊信息
            self.assistant_login()  # 登录
            # self.wooxin_ai.friends_syn(self.uin, self.member_list)  # 向后端发送好友信息
            self.sync_friends_in_batches(init=True)  # 向后端分段发送好友信息
            self.wooxin_ai.group_syn(self.group_list)  # 向后端发送群信息
            self.syn_c_remark()  # 拉取后端的备注信息，主要处理标记为C的信息，self.member_list中只保留后端标记为 C 的好友
            self.friends_process(init=True)  # 将好友数据处理为项目所需要的格式
            self.download_thread = threading.Thread(target=self.download_avatar)  # 开始下载头像
            self.download_thread.daemon = True
            self.download_thread.start()
        except Exception as e:
            error_info = f"初始化失败: {e}"
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def assistant_login(self):
        response = self.wooxin_ai.assistant_login(self.uin, self.user_name, self.nick_name, self.remark_name, self.sex,
                                                  self.province, self.city, self.attr_status,
                                                  self.seq, self.get_mac_address())
        if response is not None:
            # 处理返回的内容，错误情况
            self.queue_1.put((self.index, "LogError", response))
            return
        else:
            # 处理没有返回内容的情况
            pass

    def update_user_info(self, user, init=False, update=False):
        """
        更新用户个人信息
        """
        try:
            self.uin = user['Uin']
            self.user_name = user['UserName']
            self.nick_name = user['NickName']
            self.remark_name = user['RemarkName']
            self.sex = user['Sex']
            self.province = user['Province']
            self.city = user['City']
            self.attr_status = user['AttrStatus']

            self.head_img_url = user['HeadImgUrl']
            parsed_url = urlparse(self.head_img_url)
            params = parse_qs(parsed_url.query)
            self.seq = params.get('seq', [''])[0]  # 获取seq的值，如果不存在默认为空字符串

            # 构造自己的信息字典，即当前登录用户的字典
            self.my_info = {
                'UserName': self.user_name,
                'Avatar': itchat.get_head_img(userName=self.user_name),
                'NickName': self.nick_name,
                'RemarkName': self.remark_name,
                'Msg': {'is_outgoing': '', 'type': '', 'content': '', 'time': ''}
            }
            if init:
                # 发送给主进程（主界面）
                self.queue_1.put((self.index, "MyInfo", self.my_info))
        except Exception as e:
            error_info = f"获取用户信息失败: {e}"
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def update_friends_info_in_batches(self, friend, batch_size=500):
        """
        更新member_list好友信息
        """
        try:
            fields_to_extract_all = ['Uin', 'UserName', 'NickName', 'RemarkName', 'Sex', 'AttrStatus', 'HeadImgUrl',
                                     'seq']

            # 预先定义一个模板字典，减少每次循环中的字典创建和更新操作
            template = {field: None for field in fields_to_extract_all}

            self.member_list.clear()

            total_batches = (len(friend) + batch_size - 1) // batch_size

            def process_batch(batch_friends):
                batch_member_list = []
                for item in batch_friends:
                    friend_info = template.copy()
                    friend_info['Uin'] = item.get('Uin', 0)
                    for field in fields_to_extract_all[1:-1]:
                        friend_info[field] = item[field]
                    if 'HeadImgUrl' in item:
                        friend_info['seq'] = self.extract_seq(item['HeadImgUrl'])
                    del friend_info['HeadImgUrl']
                    batch_member_list.append(friend_info)
                return batch_member_list

            with concurrent.futures.ThreadPoolExecutor() as executor:
                futures = []
                for i in range(total_batches):
                    start_index = i * batch_size
                    end_index = min((i + 1) * batch_size, len(friend))
                    batch_friends = friend[start_index:end_index]
                    futures.append(executor.submit(process_batch, batch_friends))

                for future in concurrent.futures.as_completed(futures):
                    self.member_list.extend(future.result())

        except Exception as e:
            error_info = "更新好友信息失败，错误信息：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def syn_c_remark(self):
        # 获取后端的备注列表
        remark_list = self.wooxin_ai.syn_remark()

        # 将返回的 remark_list 保存为字典
        self.c_user_name_dict = {item['UserName']: True for item in remark_list}

        # 从 self.member_list 中筛选
        filtered_members = [
            member for member in self.member_list
            if member['UserName'] in self.c_user_name_dict
        ]

        # 更新本地的好友列表
        self.member_list = filtered_members

    def sync_friends_in_batches(self, batch_size=500, init=False):
        # 计算总批次
        try:
            total_batches = (self.friends_total_num + batch_size - 1) // batch_size

            for i in range(total_batches):
                start_index = i * batch_size
                end_index = min((i + 1) * batch_size, len(self.member_list))
                batch_members = self.member_list[start_index:end_index]

                # 调用函数处理当前批次
                self.wooxin_ai.friends_syn(self.uin, self.user_name, batch_members)
                # self.logger.info("同步了{}个好友".format(len(batch_members)))
                if init:
                    self.friends_syn_num += len(batch_members)
                    self.queue_1.put((self.index, "FriendsNum", (self.friends_syn_num, self.friends_total_num)))
        except Exception as e:
            error_info = "分段同步好友信息遇到异常，错误信息：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def friends_process(self, init=False, update=False):
        """
        只在登录时执行
        添加Msg属性
        "is_outgoing": true：表示这条消息是由当前用户发送出去的。
        "is_outgoing": false：表示这条消息是由其他人发送给当前用户的。
        """
        try:
            self.friends_show_list = [
                {
                    'UserName': user_info['UserName'],
                    'Avatar': os.path.join(f"./bots/bot{self.index}/avatar", f"{user_info['UserName']}.jpg"),
                    'seq': user_info['seq'],
                    'NickName': user_info['NickName'],
                    'RemarkName': user_info['RemarkName'],
                    'Msg': {'is_outgoing': '', 'type': '', 'content': '', 'time': ''}
                }
                for user_info in self.member_list
            ]
            if init:
                # 批量插入数据库
                data_to_insert = [
                    (user['UserName'], user['Avatar'], user['seq'], user['NickName'], user['RemarkName'])
                    for user in self.friends_show_list
                ]
                self.db_worker.do_bulk_insert('users', data_to_insert)
                self.db_worker.wait()
                self.queue_1.put((self.index, "FriendData", self.friends_show_list))
            if update:
                # 更新数据库信息
                for user in self.friends_show_list:
                    self.update_or_insert_user(user)
                self.queue_1.put((self.index, "FriendData", self.friends_show_list))
        except Exception as e:
            error_info = "更新好友列表信息失败，错误信息：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)


    def get_avatar(self, username, row):
        avatar = itchat.get_head_img(userName=username)
        self.queue_3.put((self.index, "Avatar", avatar))
        self.db_worker.do_update('users', 'avatar', avatar, 'username', username)
        self.db_worker.wait()

    def friends_syn(self):
        """
        拉取通讯录,更新信息后,发送给接口
        手动更新好友或定时更新好友时执行
        """
        try:
            # 获取好友列表
            lists = itchat.get_friends()
            user = lists.pop(0)
            friend = lists
            # 获取群聊信息
            groups = itchat.get_chatrooms(update=True)

            # 更新自己的UserName信息
            self.update_user_info(user, update=True)
            # 更新客户端的的好友列表信息
            self.update_friends_info_in_batches(friend)
            # 更新客户端的群聊列表信息
            self.update_groups_info(groups)
            # 向接口发送更新后的好友列表信息
            # self.wooxin_ai.friends_syn(self.uin, self.member_list)
            self.sync_friends_in_batches()
            # 向后端发送群聊信息
            self.wooxin_ai.group_syn(self.group_list)
            # 拉取后端的备注信息，self.member_list中只保留后端标记过的好友
            self.syn_c_remark()

            self.friends_process(update=True)
        except Exception as e:
            error_info = "拉取通讯录失败，错误信息：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def update_groups_info(self, groups, batch_size=10):
        """
        更新群聊列表信息
        """
        try:
            fields_to_extract_all = ['UserName', 'NickName', 'RemarkName', 'HeadImgUrl', 'seq']

            def process_batch(batch_groups):
                batch_group_list = []
                for item in batch_groups:
                    group_info = {
                        # 初始化字典，直接从item中获取大部分字段
                        **{field: item[field] for field in fields_to_extract_all[0:-1]},  # 使用字典解包(*)来合并字典
                        # 特殊处理seq，从HeadImgUrl提取并保持为字符串，通过字典更新操作添加
                        **({'seq': self.extract_seq(item['HeadImgUrl'])} if 'HeadImgUrl' in item else {}),
                    }
                    batch_group_list.append(group_info)
                return batch_group_list

            total_batches = (len(groups) + batch_size - 1) // batch_size

            with concurrent.futures.ThreadPoolExecutor() as executor:
                futures = []
                for i in range(total_batches):
                    start_index = i * batch_size
                    end_index = min((i + 1) * batch_size, len(groups))
                    batch_groups = groups[start_index:end_index]
                    futures.append(executor.submit(process_batch, batch_groups))

                self.group_list = []
                for future in concurrent.futures.as_completed(futures):
                    self.group_list.extend(future.result())

        except Exception as e:
            error_info = "更新群聊信息失败，错误信息：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def safe_query(self, database_path, query, params=None):
        """
        安全执行SQL查询
        """
        # 建立数据库连接
        conn = sqlite3.connect(database_path)
        # 创建游标
        cursor = conn.cursor()
        try:
            # 安全执行查询
            if params is None:
                cursor.execute(query)
            else:
                cursor.execute(query, params)
            # 获取查询结果
            result = cursor.fetchone()
            # 如果查询结果存在，则返回第一个元素
            if result:
                return result
            else:
                return None
        finally:
            # 关闭游标
            cursor.close()
            # 关闭连接
            conn.close()

    def update_or_insert_user(self, user):
        """
        在同一登录状态下，更新数据库中的好友信息
        """

        # 查询数据库中是否存在相同的 UserName
        try:
            database_path = './bots/bot{}/information.db'.format(self.index)
            query = "SELECT * FROM users WHERE username = ?"
            params = (user['UserName'],)

            result = self.safe_query(database_path, query, params)
            # print(result)

            if result:
                # 检查 Avatar 和 NickName 和 RemarkName 是否发生了变化
                if user['Avatar'] != result[2]:
                    self.db_worker.do_update('users', 'avatar', user['Avatar'], 'username', user['UserName'])
                    self.db_worker.wait()

                if user['seq'] != result[3]:
                    self.db_worker.do_update('users', 'seq', user['seq'], 'username', user['UserName'])
                    self.db_worker.wait()

                if user['NickName'] != result[4]:
                    self.db_worker.do_update('users', 'nickname', user['NickName'], 'username', user['UserName'])
                    self.db_worker.wait()

                if user['RemarkName'] != result[5]:
                    self.db_worker.do_update('users', 'remarkname', user['RemarkName'], 'username', user['UserName'])
                    self.db_worker.wait()
            else:
                # 如果不存在，则插入新记录
                self.db_worker.do_insert('users', [user['UserName'], user['Avatar'], user['seq'], user['NickName'],
                                                   user['RemarkName']])
                self.db_worker.wait()
        except Exception as e:
            error_info = "更新好友信息失败，错误信息：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def download_avatar(self):
        """
        下载用户头像
        Return：头像的本地路径
        """
        try:
            # 定义头像保存的路径
            directory = "./bots/bot{}/avatar".format(self.index)

            # 检查文件夹是否存在，如果不存在则创建
            if not os.path.exists(directory):
                os.makedirs(directory)
            with concurrent.futures.ThreadPoolExecutor(max_workers=30) as executor:
                futures = [executor.submit(self.download_single_avatar, friend, directory) for friend in
                           self.friends_show_list]
                for future in concurrent.futures.as_completed(futures):
                    future.result()
        except Exception as e:
            # self.logger.erro("获取头像失败:{}".format(e))
            pass

    def download_single_avatar(self, friend, directory, retries=3):
        filepath = os.path.join(directory, f"{friend['UserName']}.jpg")
        attempt = 0

        while attempt < retries:
            try:
                # 获取用户的微信头像
                img = itchat.get_head_img(userName=friend['UserName'])

                # 检查获取的图片是否有效
                if img:
                    with open(filepath, 'wb') as fileImage:
                        fileImage.write(img)
                    break  # 如果图片有效，退出循环
                else:
                    raise ValueError("获取的图片数据为空")

            except Exception as e:
                attempt += 1
                time.sleep(1)
                # error_info = "获取用户头像失败，错误信息：{}，重试次数：{}".format(e, attempt)
                # self.logger.error(error_info)
                # self.wooxin_ai.syn_runlog(error_info)

                # 如果达到最大重试次数，抛出最终的异常
                if attempt == retries:
                    pass
                    # raise Exception(final_error_info)

    def extract_seq(self, head_img_url):
        seq_pattern = re.compile(r'seq=(\d+)')
        match = seq_pattern.search(head_img_url)
        return match.group(1) if match else ""

    def get_mac_address(self):
        mac_num = hex(uuid.getnode()).replace('0x', '').upper()
        mac_address = ':'.join(mac_num[i:i + 2] for i in range(0, 12, 2))
        self.logger.info("本机MAC地址为：{}".format(mac_address))
        return mac_address

    def update_show_message(self, username, is_outgoing, type, content, time, display_in_chat_window=True):
        """
        收到新消息时，向主界面发送信号，传递好友列表。
        """
        new_msg = {
            "is_outgoing": is_outgoing,
            "type": type,
            "content": content,
            "time": time
        }

        def get_avatar_from_db(username):
            avatar_result = self.db_worker.do_select('users', 'avatar', 'username', username, False)
            self.db_worker.wait()
            return avatar_result[0][0] if avatar_result and avatar_result[0] else None

        # 查找并更新
        found_user = None
        for i, user in enumerate(self.friends_show_list):
            if user['UserName'] == username:
                found_user = user
                found_user['Msg'] = new_msg
                found_user['Avatar'] = get_avatar_from_db(user['UserName'])
                break

        # 如果找到了用户，则将其移动到列表的第一个位置
        if found_user:
            self.friends_show_list.remove(found_user)
            self.friends_show_list.insert(0, found_user)

        # 发送好友列表信息，用作好友列表界面的显示
        self.queue_1.put((self.index, "FriendData", self.friends_show_list))

        if display_in_chat_window:
            # 收到消息信息，在聊天窗口显示消息
            # print("display_in_chat_window=True")
            self.queue_1.put((self.index, "MessageData", self.friends_show_list[0]))

    def message_send(self, type):
        # 主动消息发送
        try:
            msg_list = self.wooxin_ai.message_pull(type)
            # self.logger.info("拉取主动消息成功{}".format(msg_list))
        except Exception as e:
            error_info = "拉取主动消息失败，错误信息：{}，详细信息：\n{}".format(e, traceback.format_exc())
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)
            return
        for msg_item in msg_list:  # 对于msg_list中的每个元素进行处理
            id_ = msg_item['id']
            to_user_name = msg_item['UserName']
            msg = msg_item['msg']

            # 检查用户是否正在被回复
            if to_user_name not in self.reply_sending_dic:
                self.reply_sending_dic[to_user_name] = 0  # 字典没有该用户，则设置为未在回复状态
            while not self.reply_sending_dic[to_user_name] == 0:  # 等待状态置0
                time.sleep(1)

            try:
                self.reply_sending_dic[to_user_name] = 2  # 状态置为2，表示正在推主动/追问消息
                isSend = self.reply_send(to_user_name, msg, id_)
                if isSend:
                    self.logger.info(
                        "[主动消息发送成功]id:{}, FromUserName: {}, ToUserName：{}, msg: {}".format(id_, self.user_name,
                                                                                                   to_user_name, msg))
                    self.wooxin_ai.message_pull_receipt(id_)
                    self.reply_sending_dic[to_user_name] = 0  # 推主动/追问消息结束，状态置0
            except Exception as e:
                error_info = "[主动消息发送失败]错误信息为:{}，详细信息：\n{}".format(e, traceback.format_exc())
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)
                self.reply_sending_dic[to_user_name] = 0
                # self.log_out()

    def get_message(self):
        """
        拉取后端的消息
        消息类型：[1， 2， 3]
            1、意向用户 全天
            2、招呼语 在配置的指定时间段内发送
            3、追加话术 全天
        """
        try:
            current_hour = datetime.now().hour
        except Exception as e:
            error_info = "获取当前时间失败，错误信息为:{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)
            current_hour = 0
        try:
            if self.message_hour_1 <= current_hour <= self.message_hour_2:  # 当前时间在设定的时间之内，拉取全部
                self.message_send([1, 2, 3])
            else:  # 不在设定的时间之内，只拉取 [1, 3]
                self.message_send([1, 3])
        except Exception as e:
            error_info = "拉取消息任务执行出错，错误信息为:{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)
            self.check_and_restart_jobs()

    def friends_syn_(self):
        try:
            self.friends_syn()
        except Exception as e:
            error_info = "通讯录同步失败，错误信息为:{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)
            self.check_and_restart_jobs()

    def friends_syn_night(self):
        try:
            current_hour = datetime.now().hour
            if 0 <= current_hour <= 6:
                try:
                    # itchat.get_friends()
                    itchat.send('', toUserName='filehelper')
                except Exception as e:
                    pass
                    # self.logger.error("本地通讯录同步失败，错误信息为:{}".format(e))
            # schedule.cancel_job(self.job_id_friends_night)
            # self.job_id_friends_night = schedule.every(random.randint(10, 30)).minutes.do(self.friends_syn_night)
        except Exception as e:
            self.check_and_restart_jobs()

    # def start_scheduled_tasks(self):
    #     """启动定时任务"""
    #     try:
    #         self.job_id_message = schedule.every(self.message_interval).minutes.do(self.get_message)
    #         self.logger.info("启动拉取消息任务")
    #         # 定时拉取好友列表, 每隔三个小时自动拉取
    #         self.job_id_friends = schedule.every(3).hours.do(self.friends_syn_)
    #         # 夜晚每隔 10-30 分钟拉取一次好友列表，只本地调用
    #         self.job_id_friends_night = schedule.every(random.randint(10, 30)).minutes.do(self.friends_syn_night)
    #     except Exception as e:
    #         error_info = "启动定时任务失败，错误信息为:{}".format(e)
    #         self.logger.error(error_info)
    #         self.wooxin_ai.syn_runlog(error_info)

    def create_schedule(self):
        self.scheduler = BackgroundScheduler()

    def start_scheduled_tasks(self):
        """启动定时任务"""
        try:
            # 启动拉取消息任务
            self.job_id_message = self.scheduler.add_job(self.get_message,
                                                         'interval',
                                                         minutes=self.message_interval,
                                                         id='job_message')
            self.logger.info("启动拉取消息任务")

            # 定时拉取好友列表与群聊列表, 每隔三个小时自动拉取
            self.job_id_friends = self.scheduler.add_job(self.friends_syn_,
                                                         'interval',
                                                         hours=3,
                                                         id='job_friends')

            # 夜晚每隔 10-30 分钟向文件传输助手发送空白消息，只本地调用
            self.job_id_friends_night = self.scheduler.add_job(self.friends_syn_night,
                                                               'interval',
                                                               minutes=random.randint(10, 30),
                                                               id='job_friends_night')

            # 启动调度器
            self.scheduler.start()
        except Exception as e:
            error_info = "启动定时任务失败，错误信息为:{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def monitor_and_restart_jobs(self):
        while True:
            try:
                time.sleep(1)
                self.check_and_restart_jobs()
            except Exception as e:
                error_info = "监控和重启定时任务失败，错误信息为:{}".format(e)
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)

    def run_scheduler(self):
        while True:
            try:
                self.scheduler.start()
            except Exception as e:
                # self.logger.error(f"调度器异常退出，错误信息为: {e}")
                time.sleep(5)  # 延时后重启调度器

    def check_and_restart_jobs(self):
        """检查并重启定时任务"""
        try:
            # 检查并重启拉取消息任务
            if not self.scheduler.get_job('job_message'):
                self.job_id_message = self.scheduler.add_job(self.get_message, 'interval',
                                                             minutes=self.message_interval, id='job_message')
                self.logger.info("重启拉取消息任务")

            # 检查并重启定时拉取好友列表任务
            if not self.scheduler.get_job('job_friends'):
                self.job_id_friends = self.scheduler.add_job(self.friends_syn_, 'interval', hours=3, id='job_friends')
                self.logger.info("重启定时拉取好友列表任务")

            # 检查并重启夜晚拉取好友列表任务
            if not self.scheduler.get_job('job_friends_night'):
                self.job_id_friends_night = self.scheduler.add_job(self.friends_syn_night, 'interval',
                                                                   minutes=random.randint(10, 30),
                                                                   id='job_friends_night')
                self.logger.info("重启夜晚保持连接任务")
        except Exception as e:
            error_info = "检查并重启定时任务失败，错误信息为:{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def update_timer(self, user_name, to_user_name, message):
        """为用户启动或更新计时器,并保存消息
            第一次接收到消息时，等待10秒，若其中用户接着发来消息，则合并，并重置定时器
            定时器结束后向后端发送合并后的消息
        """
        try:
            self.user_messages.setdefault(user_name, []).append(message)
            # 如果定时器已存在.则重置定时器
            if user_name in self.user_timers:
                self.user_timers[user_name].cancel()
                del self.user_timers[user_name]
            # 创建并启动计时器
            self.user_timers[user_name] = threading.Timer(10, self.timer_expired, args=[user_name, to_user_name])
            self.user_timers[user_name].daemon = True
            self.user_timers[user_name].start()
        except Exception as e:
            error_info = "[消息计时器出错]错误信息为:{}，详细信息：\n{}".format(e, traceback.format_exc())
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def timer_expired(self, user_name, to_user_name):
        """计时器结束处理"""
        try:
            if user_name in self.user_timers:
                del self.user_timers[user_name]
            messages = self.user_messages.pop(user_name, [])
            combined_message = "，".join(messages)
            user_msg = combined_message
            from_user_name = user_name
            self.logger.info(
                "[收到全部消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name, to_user_name,
                                                                                 user_msg))

            # 获取回复信息
            reply_content = self.wooxin_ai.process_wechat_message(user_msg, from_user_name, to_user_name)
            # 分段并发送消息
            if from_user_name not in self.reply_sending_dic:  # 回复前，查询字典，若没有该回复用户的信息，则初始为默认状态
                self.reply_sending_dic[from_user_name] = 0
            while not self.reply_sending_dic[from_user_name] == 0:  # 等待状态置0
                time.sleep(1)
            self.reply_sending_dic[from_user_name] = 1  # 准备回复，设置为正在回复状态
            self.reply_send(from_user_name, reply_content)  # 回复中
            if from_user_name in self.reply_sending_dic:  # 回复结束，该用户的回复状态置0
                self.reply_sending_dic[from_user_name] = 0
        except Exception as e:
            error_info = "[消息计时器出错]错误信息为:{}，详细信息：\n{}".format(e, traceback.format_exc())
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def reply_send(self, to_user_name, reply_content, id_=None):
        first_content = True
        isSent = False
        # 如果文本中有图片或视频链接,则进行图片链接的处理
        if "http" in reply_content or "https" in reply_content or ".jpg" in reply_content or ".png" in reply_content or ".mp4" in reply_content:
            reply_contents = split_text_with_links(reply_content)
            for reply in reply_contents:
                reply = reply.lstrip('。')
                reply = reply.lstrip(',')
                reply = reply.lstrip('、')
                reply = reply.lstrip('；')
                reply = reply.lstrip('：')
                reply = reply.lstrip('，')
                reply = reply.lstrip('\n')
                reply = reply.rstrip('\n')
                if ".png" in reply or ".jpg" in reply:  # 处理图片链接
                    image_url = reply
                    try:
                        response = requests.get(image_url)
                        image_data = BytesIO(response.content)
                        itchat.send_image(image_data, toUserName=to_user_name)
                        isSent = True
                    except Exception as e:
                        error_info = "发送图片遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                        isSent = False
                    try:
                        # 插入聊天记录到数据库中
                        timestamp_original = QDateTime.currentDateTime()
                        # timestamp = timestamp_original.toString(Qt.ISODate)
                        # self.db_worker.do_insert('message', [to_user_name, '1', image_url, timestamp])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "PICTURE", "[图片]",
                                                 timestamp)
                    except Exception as e:
                        error_info = "更新界面消息遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                elif ".mp4" in reply:  # 处理视频链接
                    mp4_url = reply
                    try:
                        mp4_path = download_file_from_url(mp4_url)
                        itchat.send_video(mp4_path, toUserName=to_user_name)
                        isSent = True
                    except Exception as e:
                        error_info = "发送视频遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                        isSent = False
                    try:
                        # 插入聊天记录到数据库中
                        timestamp_original = QDateTime.currentDateTime()
                        # timestamp = timestamp_original.toString(Qt.ISODate)
                        # self.db_worker.do_insert('message', [to_user_name, '1', mp4_url, timestamp])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "VIDEO", "[视频消息，请到手机微信查看]", timestamp)
                        if os.path.isfile(mp4_path):
                            os.remove(mp4_path)
                    except Exception as e:
                        error_info = "更新界面消息遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                elif ".pdf" in reply:  # 处理pdf文件
                    pdf_url = reply
                    try:
                        pdf_path = download_file_from_url(pdf_url)
                        itchat.send_file(pdf_path, toUserName=to_user_name)
                        isSent = True
                    except Exception as e:
                        error_info = "发送pdf文件遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                        isSent = False
                    try:
                        # 插入聊天记录到数据库中
                        timestamp_original = QDateTime.currentDateTime()
                        # timestamp = timestamp_original.toString(Qt.ISODate)
                        # self.db_worker.do_insert('message', [to_user_name, '1', pdf_url, timestamp])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "ATTACHMENT", "[文件消息，请到手机微信查看]",
                                                 timestamp)
                        if os.path.isfile(pdf_path):
                            os.remove(pdf_path)
                    except Exception as e:
                        error_info = "更新界面消息遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                elif ".txt" in reply:  # 处理txt文件
                    txt_url = reply
                    try:
                        txt_path = download_file_from_url(txt_url)
                        itchat.send_file(txt_path, toUserName=to_user_name)
                        isSent = True
                    except Exception as e:
                        error_info = "发送txt文件遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                        isSent = False
                    try:
                        # 插入聊天记录到数据库中
                        timestamp_original = QDateTime.currentDateTime()
                        # timestamp = timestamp_original.toString(Qt.ISODate)
                        # self.db_worker.do_insert('message', [to_user_name, '1', txt_url, timestamp])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "ATTACHMENT", "[文件消息，请到手机微信查看]",
                                                 timestamp)
                        if os.path.isfile(txt_path):
                            os.remove(txt_path)
                    except Exception as e:
                        error_info = "更新界面消息遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                else:  # 处理纯文本
                    try:
                        reply = reply.rstrip(',')
                        reply = reply.rstrip('，')
                        # if not id_:  # 非主动消息
                        interval = len(reply) / TYPE_SPEED
                        if first_content:  # 第一段消息
                            # interval = interval - 5 if interval > 5 else interval
                            interval = 0
                            first_content = False
                        else:  # 非第一段消息
                            pass
                        time.sleep(interval)  # 模拟人打字的时间,延迟发送消息
                        itchat.send(reply, toUserName=to_user_name)
                        isSent = True
                    except Exception as e:
                        error_info = "发送消息遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)
                        isSent = False
                    try:
                        # 插入聊天记录到数据库中
                        timestamp_original = QDateTime.currentDateTime()
                        # timestamp = timestamp_original.toString(Qt.ISODate)
                        # self.db_worker.do_insert('message', [to_user_name, '1', reply, timestamp])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "TEXT", reply, timestamp)
                    except Exception as e:
                        error_info = "更新界面消息遇到错误:{}".format(e)
                        self.logger.error(error_info)
                        self.wooxin_ai.syn_runlog(error_info)

            if not id_:  # 正常对话,即非主动消息
                self.logger.info(
                    "[回复消息] FromUserName: {}, ToUserName：{}, msg: {}".format(self.user_name, to_user_name,
                                                                                 reply_contents))
        # 纯文本处理逻辑
        # 长文本分段并回复消息
        elif len(reply_content) > WORDS_COUNT and '。' in reply_content:  # 如果文本长度大于WORDS_COUNT且有句号,则进行拆分
            # logger.info("文本长度大于{}".format(WORDS_COUNT))
            try:
                reply_content = cut_text(reply_content, WORDS_COUNT)
                for reply in reply_content:
                    reply = reply.strip()
                    # if not id_:  # 非主动消息
                    interval = len(reply) / TYPE_SPEED
                    if first_content:  # 第一段消息
                        # interval = interval - 10 if interval > 10 else interval
                        interval = 0
                        first_content = False
                    else:  # 非第一段消息
                        pass
                    time.sleep(interval)  # 模拟人打字的时间,延迟发送消息
                    itchat.send(reply, toUserName=to_user_name)
                    if not id_:  # 正常对话,即非主动消息
                        self.logger.info(
                            "[回复消息] FromUserName: {}, ToUserName：{}, msg: {}".format(self.user_name, to_user_name,
                                                                                         reply))
                    isSent = True
            except Exception as e:
                error_info = "发送消息遇到错误:{}".format(e)
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)
                isSent = False
            try:
                # 插入聊天记录到数据库中
                timestamp_original = QDateTime.currentDateTime()
                # timestamp = timestamp_original.toString(Qt.ISODate)
                # self.db_worker.do_insert('message', [to_user_name, '1', reply, timestamp])
                # self.db_worker.wait()
                # 更新界面显示的消息
                timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                self.update_show_message(to_user_name, '1', "TEXT", reply, timestamp)
            except Exception as e:
                error_info = "更新界面消息遇到错误:{}".format(e)
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)

        elif len(reply_content):  # 如果文本长度小于WORDS_COUNT,不拆分
            # if not id_:  # 非主动消息
            # interval = len(reply_content) / TYPE_SPEED
            # interval = interval - 10 if interval > 10 else interval
            # time.sleep(interval)  # 模拟人打字的时间,延迟发送消息
            # logger.info("文本长度小于等于{}}".format(WORDS_COUNT))

            try:
                itchat.send(reply_content, toUserName=to_user_name)
                if not id_:  # 正常对话,即非主动消息
                    self.logger.info(
                        "[回复消息] FromUserName: {}, ToUserName：{}, msg: {}".format(self.user_name, to_user_name,
                                                                                     reply_content))
                isSent = True
            except Exception as e:
                error_info = "发送消息遇到错误:{}".format(e)
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)
                isSent = False
            try:
                # 插入聊天记录到数据库中
                timestamp_original = QDateTime.currentDateTime()
                # timestamp = timestamp_original.toString(Qt.ISODate)
                # self.db_worker.do_insert('message', [to_user_name, '1', reply_content, timestamp])
                # self.db_worker.wait()
                # 更新界面显示的消息
                timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                self.update_show_message(to_user_name, '1', "TEXT", reply_content, timestamp)
            except Exception as e:
                error_info = "更新界面消息遇到错误:{}".format(e)
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)
        else:  # 文本为空,不进行发送
            if not id_:  # 正常对话,即非主动消息
                self.logger.info("[文本为空,不回复消息] FromUserName: {}, ToUserName：{}, msg: {}".format(self.user_name,
                                                                                                         to_user_name,
                                                                                                         reply_content))

        """# 长文本不分段
        if len(reply_content):
            itchat.send(reply_content, toUserName=from_user_name)
            logger.info("[回复消息] UserName: {}, msg: {}".format(from_user_name, reply_content))
        else:  # 文本为空,不进行发送
            logger.info("[文本为空,不回复消息] UserName: {}, msg: {}".format(from_user_name, reply_content))"""

        return isSent

    def message_monitor(self):
        """
        消息监听逻辑
        """
        @itchat.msg_register([TEXT, PICTURE, RECORDING, NOTE, VIDEO, CARD, SHARING, MAP, ATTACHMENT])
        def text_reply(msg):  # 个人消息监听
            if msg['Type'] == TEXT:  # 处理文字消息
                user_msg = msg['Text']
                from_user_name = msg['FromUserName']
                to_user_name = msg['ToUserName']

                # 非C用户只响应添加好友时的同步好友功能
                if "现在我们可以开始聊天了" in user_msg:
                    self.special_instruction(from_user_name, user_msg)
                    return
                # 非C用户不响应
                if msg["FromUserName"] not in self.c_user_name_dict:
                    return

                timestamp_original = QDateTime.currentDateTime()
                # timestamp_db = timestamp_original.toString(Qt.ISODate)

                try:
                    if from_user_name == self.user_name:  # 自己发送的消息，保存到数据库中，is_outgoing为1
                        # 自己发送的消息（非AI发送），发送给后台，表示人工接管此用户（to_user_name）的聊天
                        self.wooxin_ai.process_wechat_message(user_msg, from_user_name, to_user_name)
                        self.logger.info(
                            "[发送消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name, to_user_name,
                                                                                         user_msg))
                        # self.db_worker.do_insert('message', [to_user_name, '1', user_msg, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")
                        self.update_show_message(to_user_name, '1', "TEXT", user_msg, timestamp_show)
                        return
                    else:  # 收到的消息，保存到数据库中，is_outgoing为0
                        self.logger.info(
                            "[收到消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name, to_user_name,
                                                                                         user_msg))
                        # self.db_worker.do_insert('message', [from_user_name, '0', user_msg, timestamp_db])
                        # self.db_worker.wait()
                        timestamp_show = timestamp_original.toString("HH:mm:ss")
                        self.update_show_message(from_user_name, '0', "TEXT", user_msg, timestamp_show)
                except Exception as e:
                    error_info = "更新界面消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)

                # 判断用户是否输入了特殊指令或为新添加的好友
                if "#更新好友" in user_msg or "＃更新好友" in user_msg:
                    # self.logger.info("用户输入了特殊指令 UserName: {}, msg: {}".format(from_user_name, user_msg))
                    self.special_instruction(from_user_name, user_msg)
                    return

                # 用户计时器
                self.update_timer(from_user_name, to_user_name, user_msg)

            elif msg['Type'] == PICTURE:  # 处理图片消息
                try:
                    # 非C用户不响应
                    if msg["FromUserName"] not in self.c_user_name_dict:
                        return
                    user_msg = msg['Text']
                    from_user_name = msg['FromUserName']
                    file_name = msg['FileName']
                    to_user_name = msg['ToUserName']

                    # 创建目标目录，如果不存在
                    directory_path = "downloads"
                    os.makedirs(directory_path, exist_ok=True)  # 创建目录，如果已存在则忽略

                    # 下载图片文件到指定目录
                    file_path = os.path.join(directory_path, file_name)
                    msg.download(file_path)
                    file_path = file_path
                    file_path_mark = "file:///" + file_path

                    timestamp_original = QDateTime.currentDateTime()
                    # timestamp_db = timestamp_original.toString(Qt.ISODate)

                    if from_user_name == self.user_name:  # 自己发送的消息
                        # 自己发送的消息（非AI发送），发送给后台，表示人工接管此用户（to_user_name）的聊天
                        self.wooxin_ai.process_wechat_message(user_msg, from_user_name, to_user_name, 1, file_path)
                        self.logger.info(
                            "[发送图片消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))

                        # self.db_worker.do_insert('message', [to_user_name, '1', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "PICTURE", file_path_mark, timestamp_show)
                        return
                    else:  # 收到的消息
                        self.logger.info(
                            "[收到图片消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 插入聊天记录到数据库中
                        # self.db_worker.do_insert('message', [from_user_name, '0', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(from_user_name, '0', "PICTURE", file_path_mark, timestamp_show)
                except Exception as e:
                    error_info = "更新界面消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)

                try:
                    # 获取回复消息
                    reply_content = self.wooxin_ai.process_wechat_message(user_msg, from_user_name, to_user_name, 1,
                                                                          file_path)
                    # 分段并发送消息
                    if from_user_name not in self.reply_sending_dic:  # 回复前，查询字典，若没有该回复用户的信息，则初始为默认状态
                        self.reply_sending_dic[from_user_name] = 0
                    while not self.reply_sending_dic[from_user_name] == 0:  # 等待状态置0
                        time.sleep(1)
                    self.reply_sending_dic[from_user_name] = 1  # 准备回复，设置为正在回复状态
                    self.reply_send(from_user_name, reply_content)  # 回复中
                    if from_user_name in self.reply_sending_dic:  # 回复结束，该用户的回复状态置0
                        self.reply_sending_dic[from_user_name] = 0
                    # 回复消息后清理文件
                    if os.path.isfile(file_path):
                        os.remove(file_path)
                except Exception as e:
                    error_info = "发送消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)

            elif msg['Type'] == RECORDING:  # 处理语音消息
                try:
                    # 非C用户不响应
                    if msg["FromUserName"] not in self.c_user_name_dict:
                        return
                    user_msg = msg['Text']
                    from_user_name = msg['FromUserName']
                    file_name = msg['FileName']
                    to_user_name = msg['ToUserName']

                    # 创建目标目录，如果不存在
                    directory_path = "downloads"
                    os.makedirs(directory_path, exist_ok=True)  # 创建目录，如果已存在则忽略
                    # 下载语音文件到指定目录
                    file_path = os.path.join(directory_path, file_name)
                    msg.download(file_path)

                    timestamp_original = QDateTime.currentDateTime()
                    # timestamp_db = timestamp_original.toString(Qt.ISODate)

                    if from_user_name == self.user_name:  # 自己发送的消息
                        self.logger.info(
                            "[发送语音消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 自己发送的消息（非AI发送），发送给后台，表示人工接管此用户（to_user_name）的聊天
                        self.wooxin_ai.process_wechat_message(user_msg, from_user_name, to_user_name, 2, file_path)
                        # self.db_worker.do_insert('message', [to_user_name, '1', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "RECORDING", "[语音消息，请到手机微信查看]",
                                                 timestamp_show)
                        return
                    else:
                        self.logger.info(
                            "[收到语音消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 插入聊天记录到数据库中
                        # self.db_worker.do_insert('message', [from_user_name, '0', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式，用在好友列表里的显示
                        self.update_show_message(from_user_name, '0', "RECORDING", "[语音消息，请到手机微信查看]",
                                                 timestamp_show)
                except Exception as e:
                    error_info = "更新界面消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)

                try:
                    reply_content = self.wooxin_ai.process_wechat_message(user_msg, from_user_name, to_user_name, 2,
                                                                          file_path)
                    # 分段并发送消息
                    if from_user_name not in self.reply_sending_dic:  # 回复前，查询字典，若没有该回复用户的信息，则初始为默认状态
                        self.reply_sending_dic[from_user_name] = 0
                    while not self.reply_sending_dic[from_user_name] == 0:  # 等待状态置0
                        time.sleep(1)
                    self.reply_sending_dic[from_user_name] = 1  # 准备回复，设置为正在回复状态
                    self.reply_send(from_user_name, reply_content)  # 回复中
                    if from_user_name in self.reply_sending_dic:  # 回复结束，该用户的回复状态置0
                        self.reply_sending_dic[from_user_name] = 0
                    # 回复消息后清理文件
                    if os.path.isfile(file_path):
                        os.remove(file_path)
                except Exception as e:
                    error_info = "发送消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)

            elif msg['Type'] == VIDEO:  # 处理视频消息
                try:
                    # 非C用户不响应
                    if msg["FromUserName"] not in self.c_user_name_dict:
                        return
                    user_msg = msg['Text']
                    from_user_name = msg['FromUserName']
                    file_name = msg['FileName']
                    to_user_name = msg['ToUserName']

                    # 创建目标目录，如果不存在
                    directory_path = "downloads"
                    os.makedirs(directory_path, exist_ok=True)  # 创建目录，如果已存在则忽略
                    # 下载视频文件到指定目录
                    # file_path = os.path.join(directory_path, file_name)
                    # msg.download(file_path)

                    timestamp_original = QDateTime.currentDateTime()
                    # timestamp_db = timestamp_original.toString(Qt.ISODate)

                    if from_user_name == self.user_name:  # 自己发送的消息
                        self.logger.info(
                            "[发送视频消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 自己发送的消息（非AI发送），发送给后台，表示人工接管此用户（to_user_name）的聊天
                        self.wooxin_ai.process_wechat_message("视频消息", from_user_name, to_user_name)
                        # self.db_worker.do_insert('message', [to_user_name, '1', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "VIDEO", "[视频消息，请到手机微信查看]",
                                                 timestamp_show)
                        return
                    else:
                        self.logger.info(
                            "[收到视频消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 插入聊天记录到数据库中
                        # self.db_worker.do_insert('message', [from_user_name, '0', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式，用在好友列表里的显示
                        self.update_show_message(from_user_name, '0', "VIDEO", "[视频消息，请到手机微信查看]",
                                                 timestamp_show)
                except Exception as e:
                    error_info = "更新界面消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)


            elif msg['Type'] == ATTACHMENT:  # 处理文件消息
                try:
                    # 非C用户不相应
                    if msg["FromUserName"] not in self.c_user_name_dict:
                        return
                    user_msg = msg['Text']
                    from_user_name = msg['FromUserName']
                    file_name = msg['FileName']
                    to_user_name = msg['ToUserName']

                    # 创建目标目录，如果不存在
                    directory_path = "downloads"
                    os.makedirs(directory_path, exist_ok=True)  # 创建目录，如果已存在则忽略
                    # 下载文件到指定目录
                    # file_path = os.path.join(directory_path, file_name)
                    # msg.download(file_path)

                    timestamp_original = QDateTime.currentDateTime()
                    # timestamp_db = timestamp_original.toString(Qt.ISODate)

                    if from_user_name == self.user_name:  # 自己发送的消息
                        self.logger.info(
                            "[发送文件消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 自己发送的消息（非AI发送），发送给后台，表示人工接管此用户（to_user_name）的聊天
                        self.wooxin_ai.process_wechat_message("文件消息", from_user_name, to_user_name)
                        # self.db_worker.do_insert('message', [to_user_name, '1', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(to_user_name, '1', "ATTACHMENT", "[文件消息，请到手机微信查看]",
                                                 timestamp_show)
                        return
                    else:
                        self.logger.info(
                            "[收到文件消息] FromUserName: {}, ToUserName：{}, msg: {}".format(from_user_name,
                                                                                             to_user_name, file_name))
                        # 插入聊天记录到数据库中
                        # self.db_worker.do_insert('message', [from_user_name, '0', file_name, timestamp_db])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式，用在好友列表里的显示
                        self.update_show_message(from_user_name, '0', "ATTACHMENT", "[文件消息，请到手机微信查看]",
                                                 timestamp_show)
                except Exception as e:
                    error_info = "更新界面消息遇到错误:{}".format(e)
                    self.logger.error(error_info)
                    self.wooxin_ai.syn_runlog(error_info)

            elif msg['Type'] == NOTE:
                # 非C用户不相应
                # if msg["FromUserName"] not in self.c_user_name_dict:
                #     return
                # NOTE类型消息，处理被好友拉黑或删除的情况，以及处理新添加好友的情况
                content = "#Blacklists"
                user_msg = msg['Text']
                from_user_name = msg['FromUserName']
                try:
                    to_user_name = msg['ToUserName']
                except:
                    to_user_name = "NoName"
                if "朋友验证" in user_msg:
                    user_info = itchat.search_friends(userName=from_user_name)
                    nick_name = user_info['NickName']
                    self.logger.info("被好友[{}]删除，不再向其发送消息。".format(nick_name))
                    self.wooxin_ai.process_wechat_message(content, from_user_name, to_user_name)
                elif "拒收" in user_msg:
                    user_info = itchat.search_friends(userName=from_user_name)
                    nick_name = user_info['NickName']
                    self.logger.info("被好友[{}]拉黑，不再向其发送消息。".format(nick_name))
                    self.wooxin_ai.process_wechat_message(content, from_user_name, to_user_name)
                elif "现在可以开始聊天了" in user_msg:
                    self.friends_syn()
                    self.logger.info("通讯录同步成功")
                else:
                    pass

            elif msg['Type'] == CARD:
                # 非C用户不相应
                if msg["FromUserName"] not in self.c_user_name_dict:
                    return
                # 卡片类型消息，个人名片
                pass
                # itchat.send_raw_msg(msg['MsgType'], msg['Content'], msg['FromUserName'])

            elif msg['Type'] == SHARING:
                # 非C用户不相应
                if msg["FromUserName"] not in self.c_user_name_dict:
                    return
                # 分享类型消息，接收分享卡片链接
                # 无法发送分享卡片
                pass
                # itchat.send_raw_msg(msg['MsgType'], msg['Content'], msg['FromUserName'])
                # itchat.send(msg['MsgType'], msg['Content'], msg['FromUserName'])

            elif msg['Type'] == MAP:
                # 非C用户不相应
                if msg["FromUserName"] not in self.c_user_name_dict:
                    return
                # 地图位置类型消息
                pass
                # itchat.send_raw_msg(msg['MsgType'], msg['Content'], msg['FromUserName'])

            else:
                return

        # @itchat.msg_register([TEXT, PICTURE, RECORDING, NOTE, VIDEO, CARD, SHARING, MAP, ATTACHMENT], isGroupChat=True)
        # def text_reply(msg):  # 群消息
        #     if msg['Type'] == TEXT:  # 处理文字消息
        #         user_msg = msg['Text']
        #         nick_name = msg['User']['NickName']
        #         actual_nick_name = msg['ActualNickName']
        #         from_user_name = msg['FromUserName']
        #         actual_from_user_name = msg['ActualUserName']
        #         # self.logger.info("[收到群聊@消息：{}] UserName: {}, msg: {}".format(nick_name, actual_from_user_name, user_msg))
        #
        #         timestamp_original = QDateTime.currentDateTime()
        #         timestamp_db = timestamp_original.toString(Qt.ISODate)
        #         if from_user_name == self.user_name:  # 自己发送的消息，保存到数据库中，is_outgoing为1
        #             to_user_name = msg['ToUserName']
        #
        #             # 自己发送的消息（非AI发送），发送给后台，表示人工接管此用户（to_user_name）的聊天
        #             # self.wooxin_ai.process_wechat_message("#F", to_user_name)
        #
        #             self.db_worker.do_insert('message', [to_user_name, '1', user_msg, timestamp_db])
        #             self.db_worker.wait()
        #             # 更新界面显示的消息
        #             timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
        #             self.update_show_message(to_user_name, '1', "TEXT", user_msg, timestamp_show)
        #             return
        #         else:  # 收到的消息，保存到数据库中，is_outgoing为0
        #             self.db_worker.do_insert('message', [from_user_name, '0', user_msg, timestamp_db])
        #             self.db_worker.wait()
        #             # 更新界面显示的消息
        #             timestamp_show = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
        #             self.update_show_message(from_user_name, '0', "TEXT", user_msg, timestamp_show)
        #
        #             # 获取回复信息
        #             reply_content = self.wooxin_ai.process_wechat_message(user_msg, actual_from_user_name,
        #                                                                   is_group=True, group_user_name=from_user_name,
        #                                                                   is_at=msg['IsAt'])
        #             # 分段并发送消息
        #             self.reply_send(actual_from_user_name, reply_content)  # 回复消息

        itchat.run()

    def special_instruction(self, from_user_name, user_msg):
        # 收到特殊指令
        if user_msg == "#更新好友" or user_msg == "＃更新好友":
            try:
                # 插入聊天记录到数据库中
                # timestamp_original = QDateTime.currentDateTime()
                # timestamp = timestamp_original.toString(Qt.ISODate)
                # self.db_worker.do_insert('message', [from_user_name, '0', user_msg, timestamp])
                # self.db_worker.wait()

                self.friends_syn()

                # 插入聊天记录到数据库中
                timestamp_original = QDateTime.currentDateTime()
                # timestamp = timestamp_original.toString(Qt.ISODate)
                # self.db_worker.do_insert('message', [from_user_name, '1', "通讯录更新成功", timestamp])
                # self.db_worker.wait()
                # 更新界面显示的消息
                timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                self.update_show_message(from_user_name, '1', "TEXT", "通讯录更新成功", timestamp)

                # 界面显示完好友列表后，记录日志并发送消息
                itchat.send("通讯录更新成功", toUserName=from_user_name)
                self.logger.info("通讯录同步成功")
            except Exception as e:
                error_info = "特殊指令执行失败{}".format(e)
                self.logger.error(error_info)
                self.wooxin_ai.syn_runlog(error_info)

        elif "现在我们可以开始聊天了" in user_msg:
            # 插入聊天记录到数据库中
            # timestamp_original = QDateTime.currentDateTime()
            # timestamp = timestamp_original.toString(Qt.ISODate)
            # self.db_worker.do_insert('message', [from_user_name, '0', user_msg, timestamp])
            # self.db_worker.wait()
            # 更新界面显示的消息
            # timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
            # self.update_show_message(from_user_name, '0', "TEXT", user_msg, timestamp)
            self.friends_syn()
            self.logger.info("通讯录同步成功")

        else:
            return

    def log_in(self):
        picDir = ['./bots/bot1/QR.png', './bots/bot2/QR.png', './bots/bot3/QR.png']
        statusStorageDir = ['./bots/bot1/bot1.pkl', './bots/bot2/bot2.pkl']

        itchat.logout()
        try:
            itchat.auto_login(hotReload=False, enableCmdQR=True, picDir=picDir[self.index - 1],
                              statusStorageDir=statusStorageDir[self.index - 1],
                              loginCallback=self.loginCallback, exitCallback=self.exitCallback)
            global logining
            logining = True
        except Exception as e:
            # 提示微信未实名认证
            self.queue_1.put((self.index, "STATUS", "FAIL"))

    def log_out(self):
        try:
            if not self.voluntary_logout:
                self.wooxin_ai.log_out(is_time=True)
            else:
                self.wooxin_ai.log_out()
            itchat.logout()
        finally:
            if not self.voluntary_logout:
                self.wooxin_ai.log_out(is_time=True)
            else:
                self.wooxin_ai.log_out()
            itchat.logout()
            # 取消 APScheduler 中的任务
            if self.job_id_message:
                self.scheduler.remove_job('job_message')
                self.job_id_message = None
            if self.job_id_friends:
                self.scheduler.remove_job('job_friends')
                self.job_id_friends = None
            if self.job_id_friends_night:
                self.scheduler.remove_job('job_friends_night')
                self.job_id_friends_night = None
            # 关闭调度器
            if self.scheduler.running:
                self.scheduler.shutdown()
                self.logger.info("定时任务已结束")
            # self.terminate()  # 强制结束进程
            # self.join()
            global logining
            logining = False

    def cleanup(self):
        # 删除本地数据库文件
        file_path = "./bots/bot{}/information.db".format(self.index)
        if os.path.exists(file_path) and os.path.isfile(file_path):
            try:
                # 使用os.remove删除文件
                os.remove(file_path)
            except OSError as e:
                pass
        else:
            pass

        try:
            # 停止下载线程
            if self.download_thread and self.download_thread.is_alive():
                self.download_thread.join(timeout=5)  # 等待最多5秒
            # 停止数据库工作线程
            self.db_worker.quit()
            self.db_worker.wait()
            # 关闭所有数据库连接
            self.db_manager.close_all_connections()
        except Exception as e:
            # pass
            self.logger.error("清理资源出错：{}".format(e))

    def loginCallback(self):
        """登录成功后的回调"""
        self.queue_1.put((self.index, "STATUS", "SUCCESS"))
        login_success = True

    def exitCallback(self):
        """手动登出或掉线之后的回调"""
        try:
            if not self.voluntary_logout:
                self.wooxin_ai.log_out(is_time=True)
            else:
                self.wooxin_ai.log_out()
            self.logger.info("退出登录")
            self.queue_3.put((self.index, "LOGOUT", "LOGOUT"))
            # 取消 APScheduler 中的任务
            if self.job_id_message:
                self.scheduler.remove_job('job_message')
                self.job_id_message = None
            if self.job_id_friends:
                self.scheduler.remove_job('job_friends')
                self.job_id_friends = None
            if self.job_id_friends_night:
                self.scheduler.remove_job('job_friends_night')
                self.job_id_friends_night = None
            # 关闭调度器
            if self.scheduler.running:
                self.scheduler.shutdown()
                self.logger.info("定时任务已结束")
            global logining
            logining = False
            self.queue_1.put((self.index, "STATUS", "LOGOUT"))
            self.cleanup()
        except Exception as e:
            error_info = "退出登录失败：{}".format(e)
            self.logger.error(error_info)
            self.wooxin_ai.syn_runlog(error_info)

    def init_database(self):
        # 初始化数据库
        self.db_manager = DatabaseManager('./bots/bot{}/information.db'.format(self.index))
        self.db_manager.connect()
        # 创建表
        self.db_manager.create_table('users',
                                'id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, avatar TEXT, seq TEXT, '
                                'nickname TEXT, remarkname TEXT')
        self.db_manager.create_table('message',
                                'id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, is_outgoing INTEGER, content '
                                'TEXT, time TEXT')
        # 创建 worker
        self.db_worker = DatabaseWorker(self.db_manager)

    # def schedule_thread_func(self):
    #     """在守护线程中运行的定时任务函数"""
    #     while True:
    #         time.sleep(1)  # 每多少秒检查一次定时任务队列
    #         schedule.run_pending()  # 执行所有即将到达的定时任务

    def listen_for_commands(self):
        """新线程，用于监听命令队列,点击登出按钮时,发送登出消息"""
        while True:
            if not self.queue_2.empty():
                index, command, data = self.queue_2.get_nowait()
                if index == self.index:
                    if command == "LOGOUT":
                        # 手动登出
                        self.voluntary_logout = True
                        # self.logger.info("收到登出命令")
                        self.log_out()  # 登出
                        if self._popen is not None:
                            self._popen.terminate()
                        else:
                            pass
                        break  # 命令处理完毕，跳出循环
                    elif command == "MESSAGE":
                        # 通过输入框的发送按钮发送的消息，或通过输入框发送的图片、视频、文件消息
                        username, message = data
                        try:
                            if not message.startswith("file:///"):
                                # 发送纯文本消息
                                itchat.send(message, toUserName=username)
                            elif message.endswith(".png") or message.endswith(".jpg") or message.endswith(
                                    ".jpeg") or message.endswith(".PNG") or message.endswith(
                                ".JPG") or message.endswith(".JPEG"):
                                # 发送图片消息
                                image_path = message.lstrip("file:///")
                                itchat.send_image(image_path, toUserName=username)
                                message = "[图片]"
                            elif message.endswith(".mp4") or message.endswith(".avi") or message.endswith(
                                    ".mov") or message.endswith(".MP4") or message.endswith(".AVI") or message.endswith(
                                ".MOV"):
                                # 发送视频消息
                                video_path = message.lstrip("file:///")
                                itchat.send_video(video_path, toUserName=username)
                                message = "[视频]"
                            else:
                                # 发送文件消息
                                pdf_path = message.lstrip("file:///")
                                itchat.send_file(pdf_path, toUserName=username)
                                message = "[文件]"
                        except Exception as e:
                            error_info = "发送消息出错{}".format(e)
                            self.logger.error(error_info)
                            self.wooxin_ai.syn_runlog(error_info)

                        # 通过客户端发送的消息，做冻结处理
                        self.wooxin_ai.process_wechat_message(message, self.user_name, username)
                        self.logger.info(
                            "[发送消息] FromUserName: {}, ToUserName：{}, msg: {}".format(self.user_name, username,
                                                                                         message))
                        # 储存到数据库中
                        timestamp_original = QDateTime.currentDateTime()
                        # timestamp = timestamp_original.toString(Qt.ISODate)
                        # self.db_worker.do_insert('message', [username, '0', message, timestamp])
                        # self.db_worker.wait()
                        # 更新界面显示的消息
                        timestamp = timestamp_original.toString("HH:mm:ss")  # 重新设置时间的格式：用在好友列表里的显示
                        self.update_show_message(username, '1', "TEXT", message, timestamp,
                                                 display_in_chat_window=False)
            time.sleep(1)

    def run_log_in(self):
        self.log_in()
        # 登录完成后设置事件
        self.login_event.set()

    def release_resource(self):
        try:
            # 关闭日志处理器
            if self.logger:
                for handler in self.logger.handlers:
                    handler.close()
                self.logger.handlers.clear()
        except Exception as e:
            # print(e)
            pass

    def terminate(self):
        self.release_resource()
        super().terminate()

    def join(self, timeout=None):
        self.release_resource()
        super().join(timeout)

    def run(self):
        try:
            # 创建一个事件对象
            self.login_event = threading.Event()
            self.login_event.daemon = True
            # self.log_in()

            # 创建并启动线程
            login_thread = threading.Thread(target=self.run_log_in, args=())
            login_thread.daemon = True
            login_thread.start()

            # 等待事件被设置
            self.login_event.wait()

            # 创建数据库
            self.init_database()

            # 执行同步好友等操作
            self.initialize()

            # 向主界面发送名字信息,标识正在登录的账号
            self.queue_1.put((self.index, "NAME", self.nick_name))

            # 显示历史聊天记录
            # self.show_message_history()

            self.create_schedule()
            # 在启动监听线程之前设置定时任务
            self.start_scheduled_tasks()

            # 创建守护线程来持续运行定时任务
            # schedule_thread = threading.Thread(target=self.schedule_thread_func, args=())
            # schedule_thread.daemon = True
            # schedule_thread.start()

            # 创建守护线程来检测定时任务是否还在运行
            monitor_thread = threading.Thread(target=self.monitor_and_restart_jobs)
            monitor_thread.daemon = True
            monitor_thread.start()

            # monitor_thread = threading.Thread(target=self.run_scheduler)
            # monitor_thread.daemon = True
            # monitor_thread.start()

            # 创建守护线程来监听命令队列
            command_listener = threading.Thread(target=self.listen_for_commands)
            command_listener.daemon = True
            command_listener.start()

            # 在主线程中启动消息监听
            self.message_monitor()
        finally:
            self.release_resource()
